// NOTE: 抛出错误
// var createError = require('http-errors');
// next(new Error('自定义异常'))

// 响应体规则: https://lionoggo.blog.csdn.net/article/details/52689010

/**
 * @title error handler 出错才会进入此handler
 * @param {*} err
 * @param {*} req
 * @param {*} res
 * @param {*} next
 */
function errorHandler(err, req, res, next) {
  // set locals, 只提供开发中的错误
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  let aError = [];
  console.log(Object.keys(err));
  console.log(16, err.code, 17, err.name, 18, err.message, 19, err.errors);
  switch (err.name) {
    // sequelize 校验未通过
    case 'SequelizeValidationError':
      aError = err.errors.map(item => ({
        path: item.path,
        type: item.type,
        message: item.message,
        msg: item.type === 'notNull Violation' ? '参数错误：参数缺失、参数名不对等' : '参数校验失败',
        value: item.value,
        validatorKey: item.validatorKey,
        validatorName: item.validatorName,
        validatorArgs: item.validatorArgs,
      }));
      res.status(422).json({
        code: err.message.indexOf('notNull Violation') > -1 ? 3 : 4,
        msg: err.message,
        data: {
          errors: aError,
        },
      });
      break;

    // verify token
    case 'UnauthorizedError':
    case 'TokenExpiredError':
    case 'JsonWebTokenError':
    case 'NotBeforeError':
    case 'SyntaxError':
      res.locals.user = 'jwt failed';
      res.status(401).json({
        code: 2,
        message: err.message,
        data: null,
      });
      break;

    // passport
    case 'MongoError':
    case 'CastError':// ObjectId failed
    case 'ValidationError':
    case 'MissingUsernameError':
    case 'MissingPasswordError':
    case 'IncorrectUsernameError':
    case 'IncorrectPasswordError':
    case 'AttemptTooSoonError':
    case 'TooManyAttemptsError':
    case 'NoSaltValueStoredError':
    case 'UserExistsError':
      res.status(422).json({
        code: -1,
        msg: err.message,
        data: null,
      });
      break;

    // CSRF
    case 'ForbiddenError':
      console.log('err.code === EBADCSRFTOKEN', err.code);
      // handle CSRF token errors here(CSRF被篡改)
      res.status(403).json({
        code: 1,
        msg: err.message,
        data: 'form tampered with',
      });
      break;

    // other error
    default:
      // render the error page
      res.status(err.status || 500).render('error', {
        message: err.message,
        error: {
          status: err.status || 500,
          stack: err.stack,
        },
      });
      break;
  }
}

module.exports = errorHandler;

/**
 * NOTICE: Node Error ： Cannot set headers after they are sent to the client
 * reason: 浏览器请求一次之后，服务器却返回两次及两次以上的响应。
 */
